#include "corecontroller.h"
#include "qxmpp/QXmppMessage.h"
#include <QCoreApplication>
#include <QSqlDatabase>
#include <QFileInfo>
#include <QSqlQuery>
#include "databaseconnection.h"
#include "corexmlparser.h"
#include <QDateTime>
#include "corexmlgenerator.h"

CoreController::CoreController(QObject *parent) :
    QObject(parent)
{
    settings = new QSettings(QSettings::IniFormat, QSettings::UserScope,
                               QCoreApplication::organizationDomain(),
                               QCoreApplication::applicationName());

    /*
    * open the database-connection
    *
    * if the database file is not set in the settings,
    * we assume it is placed in the settings directory
    * and named dichat.sqlite.
    */
    QString settingsPath = QFileInfo(this->settings->fileName()).canonicalPath();
    QString dbFile = settingsPath + "/dichat.sqlite";
    dbFile = this->settings->value("dbfile",dbFile).toString();
    dbconn = new DatabaseConnection(dbFile);
    server = new CoreServer(this->settings->value("keyfile",settingsPath+"/host.key").toString(),
                            this->settings->value("certfile",settingsPath+"/host.cert").toString());

    connect(server,SIGNAL(connectXMLTools(QString)),
            this,SLOT(connectXMLTools(QString)));

}

void CoreController::connectXMLTools(QString id)
{
    qDebug() << "conneting xml tools";
    CoreXMLParser* parser = server->getXMLParser(id);

    /*Client requested the buddyList */
    connect(parser,SIGNAL(buddyListRequest()),
            this,SLOT(buddyListRequest()));

    /* Client has send a message */
    connect(parser,SIGNAL(messageReceived(QXmppMessage)),
            this,SLOT(clientMessageReceived(QXmppMessage)));

    /* Client requested connection state change */
    connect(parser,SIGNAL(setConnectionState(QString, QString, QString)),
            this,SLOT(setConnectionState(QString,QString,QString)));

    /* Client requested to get connection state */
    connect(parser,SIGNAL(getConnectionState(QString, QString)),
            this,SLOT(getConnectionState(QString,QString)));

    /* Client requested to authenticate */
    connect(parser,SIGNAL(authenticationRequest(QString,QString)),
            this,SLOT(authenticationRequest(QString,QString)));

}



/**
* @brief validate User credentials
*
* username and password are matched against the database. If they match
* a user, authenticated(int) is emitted.
*
* on error, authError(QString) is emitted.
*
* @param username the username to authenticate
* @param password the user's password
*/
void CoreController::authenticationRequest(QString username, QString password)
{
    qDebug() << "validating auth request";
    CoreXMLParser *p = qobject_cast<CoreXMLParser*>( sender() );
    Q_ASSERT( p );

    if(dbconn->authUser(username,password))
    {
        server->getXMLGenerator(server->getId(p))->generateAuthenticated(username);
    }
    else {
        server->getXMLGenerator(server->getId(p))->generateAuthError();
    }
}

void CoreController::getConnectionState(QString username, QString jid)
{
    qDebug() << "getting connection state in controler";
    //TODO read RFC what characters are really allowed for JIDs?
    QRegExp rx("^[A-Za-z0-9-]+@[A-Za-z0-9\\.-]+\\.[A-Za-z]{2,4}$");


    /*_______________________________
      |- user_one                   |
      |      |- foo@betaworx.de     |
      |      |- bar@betaworx.de     |
      |- user_two                   |
      |      |- lorem@betaworx.de   |
      |_____________________________|
    */

    QMap<QString,QString> connections ;//= dbconn->connections(username);

    if(rx.indexIn(jid) < 0)
    {
        // jid did not match the regex, => invalid format
        // default to fetching ALL connection states
        QMapIterator<QString, QString> i(connections);
        while (i.hasNext()) {
            i.next();
            server->getXMLGenerator(username)->generateShowConnectionState(i.key(),i.value());
        }
    }
    else
    {
        // only show specific jid's connection state.
        QMapIterator<QString, QString> i(connections);
        while (i.hasNext()) {
            i.next();
            if(i.key() == jid)
                server->getXMLGenerator(username)->generateShowConnectionState(i.key(),i.value());
        }
    }
}

void CoreController::setConnectionState(QString username, QString jid, QString state)
{
    qDebug() << "setting connection state in controller";
    // TODO: validate input, set state, send statechanged notification (or error :-)
}

void CoreController::stateChanged(QString from,QXmppMessage::State state,int accID,int uid)
{
    /*
    QString stateStr;
    switch(state)
    {
    case QXmppMessage::None: return;
    case QXmppMessage::Active: stateStr = "active";break;
    case QXmppMessage::Composing: stateStr = "composing";break;
    case QXmppMessage::Paused: stateStr = "paused";break;
    case QXmppMessage::Inactive: stateStr = "inactive";break;
    case QXmppMessage::Gone: stateStr = "gone";break;
    }
    this->sockets.value(uid)->write(QString(
            "<xml version='1.0'><statechanged>><jid>%1</jid><state>%2</state><accid>%3</accid></statechanged>"
            ).arg(from).arg(stateStr).arg(accID).toUtf8()+"\r\n");
*/
}

void CoreController::buddyListRequest(QString username, QString accountJid)
{
    qDebug() << "requesting buddy list in controller";
    /*
    QList<QXmppRoster::QXmppRosterEntry> buddies = dbconn->getRosterEntries(username,accountJid);

    for (int i=0;i<buddies.length();i++)
    {
        qDebug() << "buddy on list: " << buddies.at(i).bareJid();
    }
*/
    /*
    QString buddylist = "<xml version='1.0'><buddylist>";

    QSqlQuery *q = new QSqlQuery(dbconn);
    q->prepare(QString("SELECT id,name FROM groups_%1").arg(uid));
    q->exec();
    while (q->next())
    {
        buddylist.append(QString("<group name='%1'>").arg(q->value(1).toString()));
        QSqlQuery *bq = new QSqlQuery(dbconn);
        bq->prepare(QString("SELECT name,jid,accid FROM buddies_%1 WHERE grp = :grp").arg(uid));
        bq->bindValue(":grp",q->value(0).toString());
        bq->exec();
        while(bq->next())
        {
            buddylist.append(QString("<buddy><name>%1</name><jid>%2</jid><accid>%3</accid></buddy>")
                             .arg(bq->value(0).toString())
                             .arg(bq->value(1).toString())
                             .arg(bq->value(2).toString()));
        }
        buddylist.append("</group>");
    }
    buddylist.append("</buddylist>");
    */
    return;
}

void CoreController::clientMessageReceived(QXmppMessage)
{
    qDebug() << "message received from client in controller";
    return;
}

void CoreController::msgRecv(QString from,QString to, QString msg,int accID,int uid)
{
    if(from=="" || to =="" || msg =="")
    {
        return;
    }
    qDebug() << "A message for acc " << accID << " from " << from << "has been received";
    qDebug() << msg;
    QDateTime date = QDateTime::currentDateTime();
    QString datestr = date.toString(Qt::ISODate);
    /*this->sockets.value(uid)->write(QString("<xml version='1.0'><message><from>%1</from><to>%2</to><content>%3</content>"
                                            "<accid>%4</accid><date>%5</date></message>").arg(from)
                                                                                         .arg(to)
                                                                                         .arg(msg)
                                                                                         .arg(accID)
                                                                                         .arg(datestr).toUtf8()+"\r\n");

*/
}
